# _*_coding:utf-8_*_
import os
import sys
from ATS.instrumentDriver import InstCom as inst
from ATS.datamanager.DataManager import DataManager
import math
import time

workpath = os.getcwd()
sys.path.insert(0, os.path.dirname(workpath))


debug_mode = 0
fake_mode = 1


# universal普遍的
def universalcom(csmu, cmd_list, func_id=0):
    """
    func_id: 0="write",1="read",2="ask",3="ask for values"
    """
    rval = None
    if fake_mode == 1:
        func_str = ["write", "read", "ask", "ask_for_values"][func_id]
        print("csmu = " + csmu, func_str, cmd_list)
        return rval
    if func_id == 1:
        rval = inst.read(csmu)
        if debug_mode:
            print("read str:", rval)
        return rval
    for cmd_str in cmd_list:
        if func_id == 0:
            inst.write(csmu, cmd_str)
        elif func_id == 2:
            rval = inst.ask(csmu, cmd_str)
        elif func_id == 3:
            rval = inst.ask_for_values(csmu, cmd_str)
        if debug_mode:
            err = inst.ask(csmu, "ERR?")
            print("error: ", err)
    return rval


def init(Sweep, Step, Bias, Open, Meas_Range, Src_Range, Compliance, Remote_Sense, Meas_Seq, Meas_Pro, Common):
    global ind, pts_perstep, total_num
    Common["smu_list"] = Sweep.keys() + Step.keys() + Bias.keys()
    # get the first measure SMU as primary sweep
    for i, s in enumerate(Common["smu_list"]):
        if s in Meas_Seq:
            ind = i
            break
    s = Common["smu_list"].pop(ind)
    Common["smu_list"].insert(0, s)
    Common["smu_ch"] = [inst.getinstattr(s, "channel") for s in Common["smu_list"]]
    Common["meassmu_list"] = [s for s in Common["smu_list"] if s in Meas_Seq]
    Common["meassmu_ch"] = [inst.getinstattr(s, "channel") for s in Common["meassmu_list"]]
    Common["csmu"] = s

    # calc program data
    if len(Meas_Pro) > 0:
        if Common["gs_flag"] == 0:
            total_num = Common["sample_pts"]
            pts_perstep = Common["sample_pts"]
        else:
            total_num = Common["swp_pts"] * Common["step_pts"]
            pts_perstep = Common["swp_pts"]
        Common["prog_data"] = {}
    for s in Meas_Pro:
        Common["prog_data"][s] = []
        if s in Sweep:
            item = Sweep[s]
            if item[0][0] == 0:  # linear mode
                step_val = float(item[0][2] - item[0][1]) / (pts_perstep - 1)
                val = [item["start"] + step_val * i for i in range(pts_perstep)]
            else:  # myLog
                step_val = (math.log10(abs(item[0][2])) - math.log10(abs(item[0][1]))) / (pts_perstep - 1)
                val = [item["start"] * (10 ** (step_val * i)) for i in range(pts_perstep)]
            for i in range(Common["step_pts"]):
                Common["prog_data"][s].extend(val)
        elif s in Step:
            item = Step[s]
            step_val = float(item[0][1] - item[0][0]) / (pts_perstep - 1)
            for i in range(Common["step_pts"]):
                Common["prog_data"][s].extend([item[0][0] + step_val * i] * pts_perstep)
        elif s in Bias:
            Common["prog_data"][s] = [Bias[s][0]] * total_num


def setup(Sweep, Step, Bias, Open, Meas_Range, Src_Range, Compliance, Remote_Sense, Meas_Seq, Meas_Pro, Common):
    cmd_list = []
    cmd_list.append("FMT 1")  # return measurement data with header
    cmd_list.append("TSC %d" % Common.get("time_stamp", 0))
    cmd_list.append("FL 0")  # no filter connection
    cmd_list.append("AIT 0,1,%d" % Common["avg_num"])  # see note2
    universalcom(Common["csmu"], cmd_list)
    cmd_list = []
    cmd_list.append("MM 16,%s" % str(Common["meassmu_ch"])[1:-1])
    tmp = [1, 2, 4]
    for i, s in enumerate(Common["meassmu_list"]):
        cmd_list.append("CMM %d,%d" % (Common["meassmu_ch"][i], tmp[Meas_Seq[s][0]]))
    tmp = ["RI", "RV"]
    for s in Meas_Range:
        obj = inst.getinstobj(s)
        rng_code = obj.getmeasrangecode(Meas_Range[s])
        ch = Common["smu_ch"][Common["smu_list"].index(s)]
        cmd_list.append("%s %d,%d" % (tmp[Meas_Range[s][2]], ch, rng_code))
    cmd_list.append("WT %g,%g" % (Common["hold_time"], Common["delay_time"]))
    if Common["stop_comp"] == 1:
        # Abort test not only compliance occured, also overflow on ADC, oscillation on any channel.
        # Source output go to start value after aborted
        cmd_list.append("WM 2,1")
    # Setup open SMU by CL command, which will open the output relay of the SMU.
    if len(Open) > 0:
        ch_str = [str(inst.getinstattr(s, "channel")) for s in Open]
        cmd_list.append("CL %s" % ",".join(ch_str))
    universalcom(Common["csmu"], cmd_list)


def getsrccmd(Sweep, Step, Bias, Src_Range, Compliance, Common):
    # get source cmd
    global func, swp_mode, start, stop, pts
    prm_src = []
    sync_src = []
    for i, s in enumerate(Common["smu_list"]):
        obj = inst.getinstobj(s)
        rng_code = obj.getsrcrangecode(Src_Range[s])
        ch = Common["smu_ch"][i]
        if i == 0:  # the first sweep SMU, primary sweep
            tmp = ["WI", "WV"]
            if s in Sweep:
                func = tmp[Sweep[s][1]]
                swp_mode = Sweep[s][0][0] + 1  # 1=linear,2=myLog
                start = Sweep[s][0][1]
                stop = Sweep[s][0][2]
                pts = Common["swp_pts"]
            elif s in Bias:  # sample mode
                func = tmp[Bias[s][1]]
                swp_mode = 1
                start = Bias[s][0]
                stop = Bias[s][0]
                pts = Common["sample_pts"]
            cmd = "%s %d,%d,%d,%g,%g,%d,%g" % (func, ch, swp_mode, rng_code,
                                               start, stop, pts, Compliance[s][0])
            prm_src = [cmd] * Common["step_pts"]
        else:
            tmp = [2, 1]
            if s in Sweep:
                iv = tmp[Sweep[s][2]]
                start = Sweep[s][0][1]
                stop = Sweep[s][0][2]
                cmd = "WNX %d,%d,%d,%d,%g,%g,%g" % (i + 1, ch, iv, rng_code, start, stop,
                                                    Compliance[s][0])
                sync_src.append([cmd] * Common["step_pts"])
            elif s in Step:
                sync_src.append([])
                iv = tmp[Step[s][2]]
                step_step = float(Step[s][0][2] - Step[s][0][1]) / (Common["step_pts"] - 1)
                for j in range(Common["step_pts"]):
                    start = Step[s][0][1] + j * step_step
                    stop = start
                    cmd = "WNX %d,%d,%d,%d,%g,%g,%g" % (i + 1, ch, iv, rng_code, start, stop,
                                                        Compliance[s][0])
                    sync_src[-1].append(cmd)
            elif s in Bias:
                iv = tmp[Bias[s][1]]
                start = Bias[s][0]
                stop = start
                cmd = "WNX %d,%d,%d,%d,%g,%g,%g" % (i + 1, ch, iv, rng_code, start, stop,
                                                    Compliance[s][0])
                sync_src.append([cmd] * Common["step_pts"])
    Common["prm_src"] = prm_src
    Common["sync_src"] = sync_src


# def getdata(has_step, Meas_Seq, Meas_Pro, Common):
#    """
#        data format: ABCDDDDDDDDDDDD 15byte
#    """
#    cnt = len(Meas_Seq)*Common["time_stamp"]
#    t_name = []
#    if Common["time_stamp"]==1:
#        if has_step:
#            t_name = ["Time(%d)"%(i+1) for i in range(Common["step_pts"])]
#        else:
#            t_name = ["Time"]
#    result = {}
#    for s in Meas_Seq:
#        result[s] = {"I":[],"V":[],"T":[]}
#        if Meas_Seq[s][0] == 2:
#            cnt+=2
#        else:
#            cnt+=1
#    # for post prog_data
#    m_smu = Meas_Seq.keys()[0]
#    if Meas_Seq[m_smu][0] == 0:
#        m_item = "I"
#    else:
#        m_item = "V"
#    pdata_ind = 0
#    cnter = 0
#    if Common["gs_flag"] == 0:
#        pts_perstep = Common["sample_pts"]
#        cnt = cnt*pts_perstep
#    else:
#        pts_perstep = Common["swp_pts"]
#        cnt = cnt*pts_perstep*Common["step_pts"]
#    is_break = 0
#    while 1:
#        rval  = universalcom(Common["csmu"], None, 1)
#        rval = rval.split(",")
#        for d in rval:
#            ch = int(d[1])
#            s = Common["smu_list"][Common["smu_ch"].index(ch)]
#            val = float(d[3:16])
#            result[s][d[2]].append(val) #d[2] is I or V or T
#            step_i = len(result[s][d[2]])/pts_perstep
#            if d[2] == "T":
#                if s == Common["smu_list"][0]: # the primary sweep SMU
#                    name = t_name[step_i]
#            elif Meas_Seq[s][0] == 2:
#                if d[2] == "I":
#                    name = Meas_Seq[s][1][step_i*2+1]
#                elif d[2] == "V":
#                    name = Meas_Seq[s][1][step_i*2]
#            else:
#                name = Meas_Seq[s][1][step_i]
#            if val == 199.999e99: # test is aborted automatically
#                is_break = 1
#                break
#            __postdata(name, [val])
#            if len(Meas_Pro)>0 and s==m_smu and d[2]==m_item:
#                for ps in Meas_Pro:
#                    name = Meas_Pro[ps][step_i]
#                    __postdata(name, [Common["prog_data"][ps][pdata_ind]])
#                pdata_ind +=1
#        if is_break: break
#        cnter +=len(rval)
#        if cnter >=cnt: break
#    return result
def getdata(step_i, Meas_Seq, Meas_Pro, Common):
    """
        data format: ABCDDDDDDDDDDDD 15byte
        Get sweep/sample data for one step bias.
    """
    global name
    if fake_mode == 1: return
    if Common["delay_time"] > 0.05:
        get_int = Common["delay_time"]
    else:
        get_int = 0.05
    # each Meas SMU has time stamp data, the primary SMU's is used for test time post.
    cnt = len(Meas_Seq) * Common["time_stamp"]
    t_name = ""
    if Common["time_stamp"] == 1:
        if step_i < 0:  # no step terminal in test
            t_name = "Time"
        else:
            t_name = "Time(%d)" % (step_i + 1)
    result = {}
    for s in Meas_Seq:
        result[s] = {"I": [], "V": [], "T": []}
        if Meas_Seq[s][0] == 2:
            cnt += 2
        else:
            cnt += 1
    # for post prog_data
    m_smu = Meas_Seq.keys()[0]
    if Meas_Seq[m_smu][0] == 0:
        m_item = "I"
    else:
        m_item = "V"
    pdata_ind = 0
    cnter = 0
    if Common["gs_flag"] == 0:
        pts_perstep = Common["sample_pts"]
    else:
        pts_perstep = Common["swp_pts"]
    cnt = cnt * pts_perstep
    is_break = 0
    while 1:
        rval = universalcom(Common["csmu"], None, 1)
        rval = rval.split(",")
        for d in rval:
            ch = int(d[1])
            s = Common["smu_list"][Common["smu_ch"].index(ch)]
            val = float(d[3:16])
            result[s][d[2]].append(val)  # d[2] is I or V or T
            if d[2] == "T":
                if s == Common["smu_list"][0]:  # the primary sweep SMU
                    name = t_name
            elif Meas_Seq[s][0] == 2:
                if d[2] == "I":
                    name = Meas_Seq[s][1][step_i * 2 + 1]
                elif d[2] == "V":
                    name = Meas_Seq[s][1][step_i * 2]
            else:
                name = Meas_Seq[s][1][step_i]
            if val == 199.999e99:  # test is aborted automatically
                is_break = 1
                break
            __postdata(name, [val])
            if len(Meas_Pro) > 0 and s == m_smu and d[2] == m_item:
                for ps in Meas_Pro:
                    name = Meas_Pro[ps][step_i]
                    __postdata(name, [Common["prog_data"][ps][pdata_ind]])
                pdata_ind += 1
        if is_break: break
        cnter += len(rval)
        if cnter >= cnt: break
        time.sleep(get_int)
    universalcom(Common["csmu"], ["*opc?"], 2)  # ensure this time test sequence completed
    return result


# to do
def __postdata(name, val_list):
    DataManager().postarraydata(name, val_list)
    pass


#    print("***",name, str(val_list))

def srcmeas(Sweep, Step, Bias, Open, Meas_Range, Src_Range, Compliance, Remote_Sense, Meas_Seq, Meas_Pro, Common):
    getsrccmd(Sweep, Step, Bias, Src_Range, Compliance, Common)
    prm_src = Common["prm_src"]
    sync_src = Common["sync_src"]
    for i in range(Common["step_pts"]):
        cmd_list = []
        cmd_list.append(prm_src[i])
        for cl in sync_src:
            cmd_list.append(cl[i])
        if i == 0:  # reset timer
            cmd_list.append("TSR")
        cmd_list.append("XE")
        universalcom(Common["csmu"], cmd_list)
        getdata(i, Meas_Seq, Meas_Pro, Common)
    # Applies 0 V from all channels.
    universalcom(Common["csmu"], ["DZ"])


def srcmeassample(Bias, Open, Meas_Range, Src_Range, Compliance, Remote_Sense, Meas_Seq, Meas_Pro, Common):
    getsrccmd({}, {}, Bias, Src_Range, Compliance, Common)
    prm_src = Common["prm_src"]
    sync_src = Common["sync_src"]
    cmd_list = [prm_src[0]]
    for cl in sync_src:
        cmd_list.append(cl[0])
    cmd_list.append("TSR")  # reset timer
    cmd_list.append("XE")
    universalcom(Common["csmu"], cmd_list)
    step_i = -1  # flag no step here
    getdata(step_i, Meas_Seq, Meas_Pro, Common)
    # Applies 0 V from all channels.
    universalcom(Common["csmu"], ["DZ"])
